﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace ModularAndPlugin.Core.ObjectUtil
{
    public partial class ObjectUtil
    {
        private static Hashtable handlers = new Hashtable();

        private ObjectUtil()
        {
        }

        public static object CreateInstance(Type type)
        {
            IValueHandler handler = handlers[type] as IValueHandler;
            try
            {
                return handler.CreateInstance();
            }
            catch (NullReferenceException)
            {
                BuildHandler(type);
                handler = handlers[type] as IValueHandler;
                return handler.CreateInstance();
            }


        }

        /// <summary>
        /// Can get value from complex expression
        /// </summary>
        /// <param name="o"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static object GetComplexValue(object o, string expression)
        {
            string[] parts = expression.Split('.');
            for (int i = 0; i < parts.Length; i++)
            {
                IValueHandler handler = handlers[o.GetType()] as IValueHandler;
                try
                {
                    o = handler.GetValue(o, parts[i]);
                }
                catch (NullReferenceException)
                {
                    BuildHandler(o.GetType());
                    handler = handlers[o.GetType()] as IValueHandler;
                    o = handler.GetValue(o, parts[i]);
                }
            }
            return o;
        }

        /// <summary>
        /// get value from complex expression. 
        /// </summary>
        /// <param name="o"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static object GetComplexValue(object o, string[] expression)
        {
            for (int i = 0; i < expression.Length; i++)
            {
                IValueHandler handler = handlers[o.GetType()] as IValueHandler;
                try
                {
                    o = handler.GetValue(o, expression[i]);
                }
                catch (NullReferenceException)
                {
                    BuildHandler(o.GetType());
                    handler = handlers[o.GetType()] as IValueHandler;
                    o = handler.GetValue(o, expression[i]);
                }
            }
            return o;
        }

        /// <summary>
        /// get value via member name
        /// </summary>
        /// <param name="o"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static object GetValue(object o, string expression)
        {
            IValueHandler handler = handlers[o.GetType()] as IValueHandler;
            try
            {
                return handler.GetValue(o, expression);
            }
            catch (NullReferenceException)
            {
                BuildHandler(o.GetType());
                handler = handlers[o.GetType()] as IValueHandler;
                return handler.GetValue(o, expression);
            }
        }

        /// <summary>
        /// set value from complex expression
        /// </summary>
        /// <param name="o"></param>
        /// <param name="expression"></param>
        /// <param name="value"></param>
        public static void SetSimpleValue(object o, string[] expression, object value)
        {
            string[] exp = new string[expression.Length - 1];
            for (int i = 0; i < exp.Length; i++)
            {
                exp[i] = expression[i];
            }
            ObjectUtil.SetValue(GetComplexValue(o, exp), expression[exp.Length], value);
        }

        /// <summary>
        /// set value from complex expression
        /// </summary>
        /// <param name="o"></param>
        /// <param name="expression"></param>
        /// <param name="value"></param>
        public static void SetComplexValue(object o, string expression, object value)
        {
            string[] splitted = expression.Split('.');
            string[] exp = new string[splitted.Length - 1];
            for (int i = 0; i < exp.Length; i++)
            {
                exp[i] = splitted[i];
            }
            ObjectUtil.SetValue(GetComplexValue(o, exp), splitted[exp.Length], value);
        }

        /// <summary>
        /// set value via member name
        /// </summary>
        /// <param name="o"></param>
        /// <param name="expression"></param>
        /// <param name="value"></param>
        public static void SetValue(object o, string expression, object value)
        {
            IValueHandler handler = handlers[o.GetType()] as IValueHandler;
            try
            {
                handler.SetValue(o, expression, value);
            }
            catch (NullReferenceException)
            {
                BuildHandler(o.GetType());
                handler = handlers[o.GetType()] as IValueHandler;
                handler.SetValue(o, expression, value);
            }
        }

        private static void BuildHandler(Type type)
        {
            lock (handlers.SyncRoot)
            {
                AppDomain currentAppDomain = AppDomain.CurrentDomain;
                AssemblyName assyName = new AssemblyName();
                assyName.Name = type.FullName;
                AssemblyBuilder assyBuilder = currentAppDomain.DefineDynamicAssembly(assyName, AssemblyBuilderAccess.Run);
                ModuleBuilder modBuilder = assyBuilder.DefineDynamicModule(type.FullName);
                Type[] newTypeInterfaces;
                newTypeInterfaces = new Type[] { typeof(IValueHandler) };
                TypeBuilder typeBuilder =
                    modBuilder.DefineType(
                        "ValueHandler", TypeAttributes.Public);

                typeBuilder.AddInterfaceImplementation(typeof(IValueHandler));
                //PropertyInfo[] infos tmpInfos
                PropertyInfo[] infos = type.GetProperties();



                TypeBuilder pidBuilder =
                    modBuilder.DefineType(
                        "<PrivateImplementationDetails>", TypeAttributes.AutoClass | TypeAttributes.AnsiClass);
                FieldBuilder getHashtableBuilder = pidBuilder.DefineField(
                    "$$method0x6000022-1", typeof(Hashtable), FieldAttributes.Static | FieldAttributes.Assembly);
                FieldBuilder setHashtableBuilder = pidBuilder.DefineField(
                    "$$method0x6000023-1", typeof(Hashtable), FieldAttributes.Static | FieldAttributes.Assembly);
                pidBuilder.CreateType();

                MethodBuilder createInstanceMethodBuilder = typeBuilder.DefineMethod(
                    "CreateInstance", MethodAttributes.Public | MethodAttributes.Virtual,
                    typeof(object), null);
                ILGenerator createGenerator = createInstanceMethodBuilder.GetILGenerator();
                createGenerator.DeclareLocal(typeof(object));
                ConstructorInfo constructorInfo = type.GetConstructor(Type.EmptyTypes);
                if (constructorInfo != null)
                {
                    Label createRet = createGenerator.DefineLabel();
                    createGenerator.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
                    createGenerator.Emit(OpCodes.Stloc_0);
                    createGenerator.Emit(OpCodes.Br_S, createRet);
                    createGenerator.MarkLabel(createRet);
                    createGenerator.Emit(OpCodes.Ldloc_0);
                    createGenerator.Emit(OpCodes.Ret);
                }
                else
                {
                    createGenerator.Emit(OpCodes.Ldstr, "The object does not has default constructor");
                    createGenerator.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new Type[] { typeof(string) }));
                    createGenerator.Emit(OpCodes.Throw);
                }

                #region Get

                MethodBuilder getMethodBuilder = typeBuilder.DefineMethod(
                    "GetValue", MethodAttributes.Public | MethodAttributes.Virtual,
                    typeof(object), new Type[] { typeof(object), typeof(string) });
                ILGenerator getGenerator = getMethodBuilder.GetILGenerator();
                getGenerator.DeclareLocal(typeof(object));
                getGenerator.DeclareLocal(typeof(object));

                Label L_0112 = getGenerator.DefineLabel();
                Label L_0256 = getGenerator.DefineLabel();
                Label getRet = getGenerator.DefineLabel();
                Label L_0526 = getGenerator.DefineLabel();
                Label L_054e = getGenerator.DefineLabel();

                ArrayList getLabelArr = new ArrayList();
                for (int i = 0; i < infos.Length; i++)
                {
                    try
                    {
                        MethodInfo minfo = type.GetMethod("get_" + infos[i].Name);
                        if (minfo == null || minfo.GetParameters().Length > 0) continue; //忽略索引器
                        getLabelArr.Add(getGenerator.DefineLabel());
                    }
                    catch { }
                }
                Label[] getLabels = new Label[getLabelArr.Count];
                getLabelArr.CopyTo(getLabels);

                getGenerator.Emit(OpCodes.Volatile);
                getGenerator.Emit(OpCodes.Ldsfld, getHashtableBuilder);
                getGenerator.Emit(OpCodes.Brtrue, L_0112);
                getGenerator.Emit(OpCodes.Ldc_I4, infos.Length);
                getGenerator.Emit(OpCodes.Ldc_R4, .5F);
                getGenerator.Emit(OpCodes.Newobj, typeof(Hashtable).GetConstructor(new Type[] { typeof(Int32), typeof(Single) }));
                for (int i = 0, j = 0; i < infos.Length; i++)
                {
                    try
                    {
                        MethodInfo minfo = type.GetMethod("get_" + infos[i].Name);
                        if (minfo == null || minfo.GetParameters().Length > 0) continue;
                        getGenerator.Emit(OpCodes.Dup);
                        getGenerator.Emit(OpCodes.Ldstr, infos[i].Name);
                        getGenerator.Emit(OpCodes.Ldc_I4_S, j++);
                        getGenerator.Emit(OpCodes.Box, typeof(Int32));
                        getGenerator.Emit(OpCodes.Call, typeof(Hashtable).GetMethod("Add", new Type[] { typeof(object), typeof(object) }));
                    }
                    catch { }
                }
                getGenerator.Emit(OpCodes.Volatile);
                getGenerator.Emit(OpCodes.Stsfld, getHashtableBuilder);
                getGenerator.MarkLabel(L_0112);
                getGenerator.Emit(OpCodes.Ldarg_2);
                getGenerator.Emit(OpCodes.Dup);
                getGenerator.Emit(OpCodes.Stloc_1);
                getGenerator.Emit(OpCodes.Brfalse, L_0256);
                getGenerator.Emit(OpCodes.Volatile);
                getGenerator.Emit(OpCodes.Ldsfld, getHashtableBuilder); //  [mscorlib]System.Collections.Hashtable <PrivateImplementationDetails>::$$method0x6000022-1
                getGenerator.Emit(OpCodes.Ldloc_1);
                getGenerator.Emit(OpCodes.Call, typeof(Hashtable).GetMethod("get_Item", new Type[] { typeof(object) }));
                getGenerator.Emit(OpCodes.Dup);
                getGenerator.Emit(OpCodes.Stloc_1);
                getGenerator.Emit(OpCodes.Brfalse, L_0256);
                getGenerator.Emit(OpCodes.Ldloc_1);
                getGenerator.Emit(OpCodes.Unbox, typeof(Int32));
                getGenerator.Emit(OpCodes.Ldind_I4);
                getGenerator.Emit(OpCodes.Switch, getLabels);
                getGenerator.Emit(OpCodes.Br, L_0256);

                for (int i = 0, j = 0; i < infos.Length; i++)
                {
                    try
                    {
                        MethodInfo minfo = type.GetMethod("get_" + infos[i].Name);
                        if (minfo == null || minfo.GetParameters().Length > 0) continue;
                        getGenerator.MarkLabel(getLabels[j++]);
                        getGenerator.Emit(OpCodes.Ldarg_1);
                        getGenerator.Emit(OpCodes.Castclass, type);
                        getGenerator.Emit(OpCodes.Callvirt, minfo);
                        if (infos[i].PropertyType.IsValueType)
                            getGenerator.Emit(OpCodes.Box, infos[i].PropertyType);
                        getGenerator.Emit(OpCodes.Stloc_0);
                        getGenerator.Emit(OpCodes.Br, getRet);
                    }
                    catch { }
                }

                getGenerator.MarkLabel(L_0256);
                if (type.BaseType == typeof(Array))
                {
                    getGenerator.Emit(OpCodes.Ldarg_2);
                    getGenerator.Emit(OpCodes.Ldc_I4_0);
                    getGenerator.Emit(OpCodes.Callvirt, typeof(string).GetMethod("get_Chars", new Type[] { typeof(Int32) }));
                    getGenerator.Emit(OpCodes.Call, typeof(Char).GetMethod("IsDigit", new Type[] { typeof(Char) }));
                    getGenerator.Emit(OpCodes.Brfalse_S, L_0526);
                    getGenerator.Emit(OpCodes.Ldarg_1);
                    getGenerator.Emit(OpCodes.Castclass, typeof(object[]));
                    getGenerator.Emit(OpCodes.Ldarg_2);
                    getGenerator.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) }));
                    getGenerator.Emit(OpCodes.Ldelem_Ref);
                    getGenerator.Emit(OpCodes.Stloc_0);
                    getGenerator.Emit(OpCodes.Br_S, getRet);
                    getGenerator.MarkLabel(L_0526);
                }
                else
                {
                    MethodInfo intIndexer = type.GetMethod("get_Item", new Type[] { typeof(Int32) });
                    //if index is object type, GetMethod will return indexer's MethodInfo whatever type I pass
                    if (intIndexer != null && intIndexer.GetParameters()[0].ParameterType != typeof(object))
                    {
                        getGenerator.Emit(OpCodes.Ldarg_2);
                        getGenerator.Emit(OpCodes.Ldc_I4_0);
                        getGenerator.Emit(OpCodes.Callvirt, typeof(string).GetMethod("get_Chars", new Type[] { typeof(Int32) }));
                        getGenerator.Emit(OpCodes.Call, typeof(Char).GetMethod("IsDigit", new Type[] { typeof(Char) }));
                        getGenerator.Emit(OpCodes.Brfalse_S, L_0526);
                        getGenerator.Emit(OpCodes.Ldarg_1);
                        getGenerator.Emit(OpCodes.Castclass, type);
                        getGenerator.Emit(OpCodes.Ldarg_2);
                        getGenerator.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) }));
                        getGenerator.Emit(OpCodes.Callvirt, intIndexer);
                        getGenerator.Emit(OpCodes.Stloc_0);
                        getGenerator.Emit(OpCodes.Br_S, getRet);
                        getGenerator.MarkLabel(L_0526);
                    }

                    MethodInfo strIndexer = type.GetMethod("get_Item", new Type[] { typeof(string) });
                    if (strIndexer != null)
                    {
                        getGenerator.Emit(OpCodes.Ldarg_1);
                        getGenerator.Emit(OpCodes.Castclass, type);
                        getGenerator.Emit(OpCodes.Ldarg_2);
                        getGenerator.Emit(OpCodes.Callvirt, strIndexer);
                        getGenerator.Emit(OpCodes.Stloc_0);
                        getGenerator.Emit(OpCodes.Br_S, getRet);
                        getGenerator.MarkLabel(L_054e);
                    }
                }

                getGenerator.Emit(OpCodes.Ldstr, "The property named ");
                getGenerator.Emit(OpCodes.Ldarg_2);
                getGenerator.Emit(OpCodes.Ldstr, " does not exists");
                getGenerator.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) }));
                getGenerator.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new Type[] { typeof(string) }));
                getGenerator.Emit(OpCodes.Throw);

                getGenerator.MarkLabel(getRet);
                getGenerator.Emit(OpCodes.Ldloc_0);
                getGenerator.Emit(OpCodes.Ret);

                #endregion

                #region Set

                MethodBuilder setMethodBuilder = typeBuilder.DefineMethod(
                    "SetValue", MethodAttributes.Public | MethodAttributes.Virtual, null
                    , new Type[] { typeof(object), typeof(string), typeof(object) });
                ILGenerator setGenerator = setMethodBuilder.GetILGenerator();
                setGenerator.DeclareLocal(typeof(object));

                Label L_0220 = setGenerator.DefineLabel();
                Label L_053b = setGenerator.DefineLabel();
                Label L_0568 = setGenerator.DefineLabel();
                Label L_0593 = setGenerator.DefineLabel();
                Label setRet = setGenerator.DefineLabel();

                ArrayList setLabelList = new ArrayList();
                for (int i = 0; i < infos.Length; i++)
                {
                    try
                    {
                        MethodInfo minfo = type.GetMethod("set_" + infos[i].Name);
                        if (minfo == null || minfo.GetParameters().Length > 1) continue;
                        setLabelList.Add(setGenerator.DefineLabel());
                    }
                    catch { }
                }
                Label[] setLabels = new Label[setLabelList.Count];
                setLabelList.CopyTo(setLabels);

                setGenerator.Emit(OpCodes.Volatile);
                setGenerator.Emit(OpCodes.Ldsfld, setHashtableBuilder);
                setGenerator.Emit(OpCodes.Brtrue, L_0220);
                setGenerator.Emit(OpCodes.Ldc_I4, infos.Length);
                setGenerator.Emit(OpCodes.Ldc_R4, 1F);
                setGenerator.Emit(OpCodes.Newobj, typeof(Hashtable).GetConstructor(new Type[] { typeof(Int32), typeof(Single) }));
                for (int i = 0, j = 0; i < infos.Length; i++)
                {
                    MethodInfo minfo = type.GetMethod("set_" + infos[i].Name);
                    if (minfo == null || minfo.GetParameters().Length > 1) continue;
                    setGenerator.Emit(OpCodes.Dup);
                    setGenerator.Emit(OpCodes.Ldstr, infos[i].Name);
                    setGenerator.Emit(OpCodes.Ldc_I4_S, j++);
                    setGenerator.Emit(OpCodes.Box, typeof(Int32));
                    setGenerator.Emit(OpCodes.Call, typeof(Hashtable).GetMethod("Add", new Type[] { typeof(object), typeof(object) }));
                }
                setGenerator.Emit(OpCodes.Volatile);
                setGenerator.Emit(OpCodes.Stsfld, setHashtableBuilder);

                setGenerator.MarkLabel(L_0220);
                setGenerator.Emit(OpCodes.Ldarg_2);
                setGenerator.Emit(OpCodes.Dup);
                setGenerator.Emit(OpCodes.Stloc_0);
                setGenerator.Emit(OpCodes.Brfalse, L_053b);
                setGenerator.Emit(OpCodes.Volatile);
                setGenerator.Emit(OpCodes.Ldsfld, setHashtableBuilder); //  [mscorlib]System.Collections.Hashtable <PrivateImplementationDetails>::$$method0x6000022-1
                setGenerator.Emit(OpCodes.Ldloc_0);
                setGenerator.Emit(OpCodes.Call, typeof(Hashtable).GetMethod("get_Item", new Type[] { typeof(object) }));
                setGenerator.Emit(OpCodes.Dup);
                setGenerator.Emit(OpCodes.Stloc_0);
                setGenerator.Emit(OpCodes.Brfalse, L_053b);
                setGenerator.Emit(OpCodes.Ldloc_0);
                setGenerator.Emit(OpCodes.Unbox, typeof(Int32));
                setGenerator.Emit(OpCodes.Ldind_I4);
                setGenerator.Emit(OpCodes.Switch, setLabels);
                setGenerator.Emit(OpCodes.Br, L_053b);

                for (int i = 0, j = 0; i < infos.Length; i++)
                {
                    MethodInfo minfo = type.GetMethod("set_" + infos[i].Name);
                    if (minfo == null || minfo.GetParameters().Length > 1) continue;
                    setGenerator.MarkLabel(setLabels[j++]);
                    setGenerator.Emit(OpCodes.Ldarg_1);
                    setGenerator.Emit(OpCodes.Castclass, type); // NoReflection.TestClass
                    setGenerator.Emit(OpCodes.Ldarg_3);
                    if (infos[i].PropertyType.IsValueType)
                    {
                        setGenerator.Emit(OpCodes.Unbox, infos[i].PropertyType);
                        if (infos[i].PropertyType == typeof(Int64))
                            setGenerator.Emit(OpCodes.Ldind_I8);
                        if (infos[i].PropertyType == typeof(Int32))
                            setGenerator.Emit(OpCodes.Ldind_I4);
                        if (infos[i].PropertyType == typeof(Int16))
                            setGenerator.Emit(OpCodes.Ldind_I2);
                        if (infos[i].PropertyType == typeof(Byte))
                            setGenerator.Emit(OpCodes.Ldind_U1);
                        if (infos[i].PropertyType == typeof(SByte))
                            setGenerator.Emit(OpCodes.Ldind_I1);
                        if (infos[i].PropertyType == typeof(Boolean))
                            setGenerator.Emit(OpCodes.Ldind_I1);
                        if (infos[i].PropertyType == typeof(UInt64))
                            setGenerator.Emit(OpCodes.Ldind_I8);
                        if (infos[i].PropertyType == typeof(UInt32))
                            setGenerator.Emit(OpCodes.Ldind_U4);
                        if (infos[i].PropertyType == typeof(UInt16))
                            setGenerator.Emit(OpCodes.Ldind_U2);
                        if (infos[i].PropertyType == typeof(Decimal))
                            setGenerator.Emit(OpCodes.Ldobj, typeof(Decimal));
                        if (infos[i].PropertyType == typeof(DateTime))
                            setGenerator.Emit(OpCodes.Ldobj, typeof(DateTime));

                    }
                    else
                    {
                        setGenerator.Emit(OpCodes.Castclass, infos[i].PropertyType); // NoReflection.TestClass
                    }
                    setGenerator.Emit(OpCodes.Callvirt, minfo);
                    setGenerator.Emit(OpCodes.Br, setRet);

                }

                setGenerator.MarkLabel(L_053b);
                if (type.BaseType == typeof(Array))
                {
                    setGenerator.Emit(OpCodes.Ldarg_2);
                    setGenerator.Emit(OpCodes.Ldc_I4_0);
                    setGenerator.Emit(OpCodes.Callvirt, typeof(string).GetMethod("get_Chars", new Type[] { typeof(Int32) }));
                    setGenerator.Emit(OpCodes.Call, typeof(Char).GetMethod("IsDigit", new Type[] { typeof(Char) }));
                    setGenerator.Emit(OpCodes.Brfalse_S, L_0568);
                    setGenerator.Emit(OpCodes.Ldarg_1);
                    setGenerator.Emit(OpCodes.Castclass, typeof(object[]));
                    setGenerator.Emit(OpCodes.Ldarg_2);
                    setGenerator.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) }));
                    setGenerator.Emit(OpCodes.Ldarg_3);
                    setGenerator.Emit(OpCodes.Stelem_Ref);
                    setGenerator.MarkLabel(L_0568);
                    setGenerator.Emit(OpCodes.Br, setRet);
                }
                else
                {
                    PropertyInfo testInfo;
                    testInfo = type.GetProperty("Item", new Type[] { typeof(Int32) });
                    if (testInfo != null)
                    {
                        MethodInfo intSetIndexer = type.GetMethod("set_Item", new Type[] { typeof(Int32), testInfo.PropertyType });
                        if (intSetIndexer != null && intSetIndexer.GetParameters()[0].ParameterType != typeof(object))
                        {
                            setGenerator.Emit(OpCodes.Ldarg_2);
                            setGenerator.Emit(OpCodes.Ldc_I4_0);
                            setGenerator.Emit(OpCodes.Callvirt, typeof(string).GetMethod("get_Chars", new Type[] { typeof(Int32) }));
                            setGenerator.Emit(OpCodes.Call, typeof(Char).GetMethod("IsDigit", new Type[] { typeof(Char) }));
                            setGenerator.Emit(OpCodes.Brfalse_S, L_0568);
                            setGenerator.Emit(OpCodes.Ldarg_1);
                            setGenerator.Emit(OpCodes.Castclass, type);
                            setGenerator.Emit(OpCodes.Ldarg_2);
                            setGenerator.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) }));
                            setGenerator.Emit(OpCodes.Ldarg_3);
                            setGenerator.Emit(OpCodes.Castclass, typeof(string));
                            setGenerator.Emit(OpCodes.Callvirt, intSetIndexer);
                            setGenerator.Emit(OpCodes.Br, setRet);
                            setGenerator.MarkLabel(L_0568);
                        }
                    }
                    testInfo = type.GetProperty("Item", new Type[] { typeof(String) });
                    if (testInfo != null)
                    {
                        MethodInfo strSetIndexer = type.GetMethod("set_Item", new Type[] { typeof(string), testInfo.PropertyType });
                        if (strSetIndexer != null)
                        {

                            setGenerator.Emit(OpCodes.Ldarg_1);
                            setGenerator.Emit(OpCodes.Castclass, type);
                            setGenerator.Emit(OpCodes.Ldarg_2);
                            setGenerator.Emit(OpCodes.Ldarg_3);
                            if (testInfo.PropertyType.IsValueType)
                            {
                                setGenerator.Emit(OpCodes.Unbox, testInfo.PropertyType);
                                if (testInfo.PropertyType == typeof(Int64))
                                    setGenerator.Emit(OpCodes.Ldind_I8);
                                if (testInfo.PropertyType == typeof(Int32))
                                    setGenerator.Emit(OpCodes.Ldind_I4);
                                if (testInfo.PropertyType == typeof(Int16))
                                    setGenerator.Emit(OpCodes.Ldind_I2);
                                if (testInfo.PropertyType == typeof(Byte))
                                    setGenerator.Emit(OpCodes.Ldind_U1);
                                if (testInfo.PropertyType == typeof(SByte))
                                    setGenerator.Emit(OpCodes.Ldind_I1);
                                if (testInfo.PropertyType == typeof(Boolean))
                                    setGenerator.Emit(OpCodes.Ldind_I1);
                                if (testInfo.PropertyType == typeof(UInt64))
                                    setGenerator.Emit(OpCodes.Ldind_I8);
                                if (testInfo.PropertyType == typeof(UInt32))
                                    setGenerator.Emit(OpCodes.Ldind_U4);
                                if (testInfo.PropertyType == typeof(UInt16))
                                    setGenerator.Emit(OpCodes.Ldind_U2);
                                if (testInfo.PropertyType == typeof(Decimal))
                                    setGenerator.Emit(OpCodes.Ldobj, typeof(Decimal));
                                if (testInfo.PropertyType == typeof(DateTime))
                                    setGenerator.Emit(OpCodes.Ldobj, typeof(DateTime));
                            }
                            else
                            {
                                setGenerator.Emit(OpCodes.Castclass, testInfo.PropertyType);
                            }

                            setGenerator.Emit(OpCodes.Callvirt, strSetIndexer);
                            setGenerator.Emit(OpCodes.Br, setRet);
                            setGenerator.MarkLabel(L_0593);
                        }
                    }
                }
                setGenerator.Emit(OpCodes.Ldstr, "The property named ");
                setGenerator.Emit(OpCodes.Ldarg_2);
                setGenerator.Emit(OpCodes.Ldstr, " does not exists");
                setGenerator.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) }));
                setGenerator.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new Type[] { typeof(string) }));
                setGenerator.Emit(OpCodes.Throw);
                setGenerator.MarkLabel(setRet);
                setGenerator.Emit(OpCodes.Ret);

                #endregion
                Type t = typeBuilder.CreateType();
                //assyBuilder.Save("ValueHandler." + type.FullName + ".dll");
                IValueHandler result = Activator.CreateInstance(t) as IValueHandler;
                handlers.Add(type, result);
            }
        }
    }
}
